#include "nm_cppcrt.h"

#pragma section(".CRT$XCA",long,read)
KCRT_FUNCTION xc_a[] = { 0 };
#pragma section(".CRT$XCZ",long,read)
KCRT_FUNCTION xc_z[] = { 0 };
#pragma data_seg()

#pragma comment(linker, "/merge:.CRT=.data")


AtExitCall* AtExitCall::m_ExitList = 0;


#ifdef __cplusplus
extern "C" {
#endif

	PDRIVER_UNLOAD g_user_driver_unload = 0;

	void __cdecl crtlib_startup()
	{
		KCRT_FUNCTION* crt_func;

		for(crt_func = xc_a; crt_func < xc_z; crt_func++) {
			if(*crt_func) {
				(*crt_func)();
			}
		}
	}

	void __cdecl crtlib_finalize()
	{
		AtExitCall::do_exit_calls();
	}


	void crt_driver_unload(PDRIVER_OBJECT drvobj)
	{
		g_user_driver_unload(drvobj);
		crtlib_finalize();
	}

	int __cdecl atexit(KCRT_FUNCTION crt_func)
	{
		return (new AtExitCall(crt_func) == 0) ? (*crt_func)(), 1 : 0;
	}

	NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath)
	{
		NTSTATUS ns;
		crtlib_startup();
		ns = NM_DriverEntry(DriverObject, RegPath);
		
		if(!NT_SUCCESS(ns)) {
			crtlib_finalize();
		}
		g_user_driver_unload = DriverObject->DriverUnload;
		
		if(g_user_driver_unload != NULL) {
			DriverObject->DriverUnload = crt_driver_unload;
		}
		
		return ns;
	}

#ifdef __cplusplus
}
#endif